package com.ruoyi.yn.util;

/**
 * @author Ming
 * @since 2023-04-25 16:15:17
 */
public class LocationUtils {

    private static final double EARTH_RADIUS = 6371.0; // 地球半径，单位 km

    /**
     * 计算两个经纬度之间的距离（单位：km）
     *
     * @param lon1 第一个点的经度
     * @param lat1 第一个点的纬度
     * @param lon2 第二个点的经度
     * @param lat2 第二个点的纬度
     * @return 两个点之间的距离，单位：km
     */
    public static double calculateDistanceKm(double lon1, double lat1, double lon2, double lat2) {
        double radLat1 = Math.toRadians(lat1);
        double radLat2 = Math.toRadians(lat2);
        double a = radLat1 - radLat2;
        double b = Math.toRadians(lon1) - Math.toRadians(lon2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s *= EARTH_RADIUS;
        return s;
    }

    /**
     * 计算两个经纬度之间的距离（单位：km）
     *
     * @param lon1 第一个点的经度
     * @param lat1 第一个点的纬度
     * @param lon2 第二个点的经度
     * @param lat2 第二个点的纬度
     * @return 两个点之间的距离，单位：m
     */
    public static double calculateDistanceM(double lon1, double lat1, double lon2, double lat2) {
        double radLat1 = Math.toRadians(lat1);
        double radLat2 = Math.toRadians(lat2);
        double a = radLat1 - radLat2;
        double b = Math.toRadians(lon1) - Math.toRadians(lon2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s *= EARTH_RADIUS * 1000; // 将结果转换为米
        return s;
    }

    /**
     * 获取最近的经纬度坐标
     *
     * @param lon1 给定点的经度
     * @param lat1 给定点的纬度
     * @param lon2 经度列表
     * @param lat2 纬度列表
     * @return 最近的经纬度坐标
     */
    public static double[] getNearestLocation(double lon1, double lat1, double[] lon2, double[] lat2) {
        double minDistance = Double.MAX_VALUE;
        double[] nearestLocation = new double[2];
        for (int i = 0; i < lon2.length; i++) {
            double distance = calculateDistanceKm(lon1, lat1, lon2[i], lat2[i]);
            if (distance < minDistance) {
                minDistance = distance;
                nearestLocation[0] = lon2[i];
                nearestLocation[1] = lat2[i];
            }
        }
        return nearestLocation;
    }

    /**
     * 获取最近的位置唯一标识符
     *
     * @param lon 给定点的经度
     * @param lat 给定点的纬度
     * @param locations 经纬度列表
     * @param ids 唯一标识符列表
     * @return 最近位置的唯一标识符
     */
    public static String getNearestLocationId(double lon, double lat, double[] locations, String[] ids) {
        double minDistance = Double.MAX_VALUE;
        String nearestId = null;
        for (int i = 0; i < locations.length; i += 2) {
            double distance = calculateDistanceKm(lon, lat, locations[i], locations[i + 1]);
            if (distance < minDistance) {
                minDistance = distance;
                nearestId = ids[i / 2];
            }
        }
        return nearestId;
    }

}